﻿using LiteBlog.Repositories.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LiteBlog.Common.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using Moq;
using LiteBlog.Repositories.Common;
using LiteBlog.Repositories;

namespace LiteBlog.Repositories.Tests
{
    [TestClass]
    public class StatDataLoadCompTests : LoadCompTests<Stat, StatRepository> 
    {
        private static readonly int VisitCount = 10;
        private static readonly int HitCount = 20;
        private static readonly int MonthlyVisitCount = 3;

        private Mock<BlogRepository> _blogMock; 

        [TestMethod]
        public void StatIsCorrect()
        {
            SetupLoad();
            var stat = _comp.Load();
            Assert.IsNotNull(stat);
            Assert.AreEqual(VisitCount, stat.Visits);
            Assert.AreEqual(HitCount, stat.Hits);
        }

        [TestMethod]
        public void GetPublishedIsCalled()
        {
            SetupLoad();
            _comp.Load();
            _blogMock.Verify(b => b.GetPublished(), Times.Once);
        }

        [TestMethod]
        public void ChangeViewsIsCalled()
        {
            var stat = SetupSave();
            _comp.Save(stat);
            _blogMock.Verify(b => b.ChangeViews(It.IsAny<Dictionary<string, PostInfo>>()), Times.Once);
        }

        protected override void SetupLoad()
        {
            var root = new XElement(Elem.Stats,
                            new XElement(Elem.Summary,
                                new XElement(Elem.Visits,
                                    new XAttribute(Attr.Count, VisitCount)),
                                new XElement(Elem.Hits,
                                    new XAttribute(Attr.Count, HitCount))),
                            new XElement(Elem.Feeds),
                            new XElement(Elem.MonthlyViews));
            _mock.Setup(x => x.Load(_data.Path))
                 .Returns(root);

            _blogMock = Mock.Get<BlogRepository>(_data.BlogData);
            _blogMock.Setup(b => b.GetPublished())
                     .Returns(new List<PostInfo>());
        }

        protected override Stat SetupSave()
        {
            var root = new XElement(Elem.Stats,
                         new XElement(Elem.Summary,
                             new XElement(Elem.Visits,
                                 new XAttribute(Attr.Count, 0)),
                             new XElement(Elem.Hits,
                                 new XAttribute(Attr.Count, 0))),
                         new XElement(Elem.Feeds),
                         new XElement(Elem.MonthlyViews,
                             new XElement(Elem.Stat,
                                 new XAttribute(Attr.Id2, 1),
                                 new XAttribute(Attr.Count, 0))));
        
            _mock.Setup(x => x.Load(_data.Path))
                 .Returns(root);

            _blogMock = Mock.Get<BlogRepository>(_data.BlogData);

            var stat = new Stat();
            stat.Visits = VisitCount;
            stat.Hits = HitCount;
            stat.Feeds = new Dictionary<string, int>();
            stat.ViewsThisMonth = MonthlyVisitCount;
            stat.Path = _data.Path;
            return stat;
        }

        protected override bool VerifySave(XElement root)
        {
            bool result = false;
            var summaryElem = root.Element(Elem.Summary);
            result = VisitCount == (int)summaryElem.Element(Elem.Visits)
                                                   .Attribute(Attr.Count);
            result = result && (HitCount == (int)summaryElem.Element(Elem.Hits)
                                                            .Attribute(Attr.Count));
            var monthlyElem = root.Element(Elem.MonthlyViews)
                                  .Elements(Elem.Stat)
                                  .Last();
            result = result && (MonthlyVisitCount == (int)monthlyElem.Attribute(Attr.Count));
            return result;
        }
    }
}
